#include "header.h"

#define ALINEACION		64

Header::Header(std::string& nombre):Archivo(nombre, 0 ){
	this->agregar_observador(Buffer::get_instance());
	
	tam_bloque_mae = 0;
	tam_bloque_ind = 0;
	tipo_archivo_mae = NINGUNO;
	tipo_indice_sec = NINGUNO;
	num_campo_ind = 0; 
	formato = "";
}
		
Header::~Header(){
	this->cerrar();	
}
		
void Header::abrir() throw(ExcepAbriendoArch){
	
	std::string dest = "./DATA/" + this->get_nombre();
	fd = ManejadorArchivos::get_instance()->abrir_archivo(dest);
	
	if ( fd == -1 )
		throw ExcepAbriendoArch(ManejadorErrores::get_msg_error(errno) + " Archivo: " + this->get_nombre());
	
	this->tam_bloque = sizeof(unsigned int) * 2;
	Bloque * bloque_header;
	bloque_header = Buffer::get_instance()->get_bloque(*this,0);
	char * contenido = bloque_header->get_contenido();
	memcpy(&this->tam_bloque,contenido + sizeof(unsigned int), sizeof(unsigned int));
	delete[] contenido;
	this->set_cambio();
	this->avisar_observadores(NULL);
	delete bloque_header;
}
		
void Header::crear() throw(ExcepCreandoArch, ExcepSintaxisParser, ExcepBloqueTam){
	
	
	std::string dest = "./DATA/" + this->get_nombre();
	this->fd = ManejadorArchivos::get_instance()->crear_archivo(dest);
	if ( this->fd == -1 )
		throw ExcepCreandoArch(ManejadorErrores::get_msg_error(errno) + " Archivo: " + this->get_nombre());
}

void Header::guardar(std::string &formato, ArchivoDatos * arch) throw(ExcepArchCerrado){
	
	unsigned int tam = calcular_tam_header(formato);
	Bloque * bloque_header = generar_bloque(tam, formato, arch);
	this->tam_bloque = bloque_header->get_size();
	Buffer::get_instance()->guardar_bloque(*this,bloque_header);
	delete bloque_header;
}
		
void Header::cerrar(){
	if(fd != -1){
		this->set_cambio();
		this->avisar_observadores(NULL);
		ManejadorArchivos::get_instance()->cerrar_archivo(this->fd);
		this->fd = -1;
	}	
}
												
TiposArchivo Header::get_tipo_archivo(){
	return HEADER;
}
 		
void Header::eliminar (){
	this->cerrar();
	std::string mi_ruta = "./DATA/" + this->get_nombre();
	remove(mi_ruta.c_str()); 	
}

unsigned int Header::calcular_tam_header(std::string &formato){
	unsigned int tam = sizeof(unsigned int); //para el tamaño del header
	tam += 	sizeof(unsigned int); //para el tam del bloque
	tam += 	sizeof(unsigned int); //para el tam del bloque del ind
	tam +=  sizeof(TiposArchivo); //para el tipo de archivo
	tam +=  sizeof(TiposArchivo); //para el tipo de indice
	tam +=  sizeof(int); //para el num de campo del indice sec
	tam +=  sizeof(unsigned int); //para el tam de la cadena
	tam += formato.size(); //para el formato
	
	tam += 4;
	return tam;
}

Bloque * Header::generar_bloque(unsigned int tam,std::string &formato,ArchivoDatos * arch){
	
	unsigned tam_alineado = 0;
	if( (tam % ALINEACION) == 0 )
		tam_alineado = ALINEACION;
	else
		tam_alineado = ALINEACION * (tam / ALINEACION + 1);
	
	Bloque * bloque = new Bloque(0, tam_alineado);
	unsigned int pos = 0;
	bloque->escribir((char *)(&tam_alineado),pos,sizeof(unsigned int));
	pos += sizeof(unsigned int);
	unsigned int tam_bloque = arch->get_tam_bloque();
	bloque->escribir((char *)(&tam_bloque),pos,sizeof(unsigned int));
	pos += sizeof(unsigned int);
	unsigned int tam_ind = arch->get_tam_indice();
	bloque->escribir((char *)(&tam_ind),pos,sizeof(unsigned int));
	pos += sizeof(unsigned int);
	TiposArchivo tipo = arch->get_tipo_archivo();
	bloque->escribir((char *)(&tipo),pos,sizeof(TiposArchivo));
	pos += sizeof(TiposArchivo);
	int num_campo = 0;
	if(arch->get_indice() == NULL)
		tipo = NINGUNO;
	else{
		tipo = arch->get_indice()->get_tipo_archivo();
		num_campo = arch->get_indice()->get_numero_campo();
	}
	bloque->escribir((char *)(&tipo),pos,sizeof(TiposArchivo));
	pos += sizeof(TiposArchivo);
	bloque->escribir((char *)(&num_campo),pos,sizeof(int));
	pos += sizeof(int);
	unsigned int cant_letras = formato.size();
	bloque->escribir((char *)(&cant_letras),pos,sizeof(unsigned int));
	pos += sizeof(unsigned int);
	bloque->escribir(formato.c_str(),pos,cant_letras);
		
	return bloque;
}

void Header::hidratar(std::string &nombre) throw(ExcepArchInexistente){
	
	Bloque * b = Buffer::get_instance()->get_bloque(*this, 0 );
	
	//TiposArchivo tipo, tipo_indice;
	//unsigned int tamano_bloque=0;
	//unsigned int tamano_paquete=0;
	//int num_campo = -1;
	char * formato_char = NULL;
	
	unsigned int pos = sizeof(unsigned int);
	b->leer( (char *)&tam_bloque_mae, pos, sizeof(unsigned int) );
	pos += sizeof(unsigned int);
	b->leer( (char *)&tam_bloque_ind, pos, sizeof(unsigned int));
	pos += sizeof(unsigned int);
	b->leer((char *)&tipo_archivo_mae, pos, sizeof(TiposArchivo));
	pos += sizeof(TiposArchivo);
	b->leer((char *)&tipo_indice_sec, pos, sizeof(TiposArchivo));
	pos += sizeof(TiposArchivo);	
	b->leer((char *)&num_campo_ind, pos, sizeof(int));
	pos += sizeof(int);	
	unsigned int cant_letras=0;
	b->leer((char *)&cant_letras, pos, sizeof(unsigned int));
	pos += sizeof(unsigned int);
	formato_char = new char[cant_letras + 1];
	formato_char[cant_letras] = 0;
	for(unsigned int i = 0; i <= cant_letras;i++)
		formato_char[i] = 0;
	b->leer(formato_char,pos,cant_letras);
	//formato.assign ( formato_char, cant_letras );// = formato_char;
	formato = formato_char;
		
	delete[] formato_char;
	delete b;
}

unsigned int Header::get_espacio_libre()  throw(ExcepArchCerrado, ExcepLeerBloque){
	return 1;	
}


unsigned int Header::get_tam_bloque_mae(){
	return tam_bloque_mae;
}
unsigned int Header::get_tam_bloque_ind(){
	return tam_bloque_ind;
}
TiposArchivo Header::get_tipo_archivo_mae(){
	return tipo_archivo_mae;	
}
TiposArchivo Header::get_tipo_indice_sec(){
	return tipo_indice_sec;
}
int Header::get_num_campo_ind(){
	return num_campo_ind;
}
std::string Header::get_formato(){
	return formato;	
}

